package com.cskaoyan.javase.object._2tostring;

import java.util.DuplicateFormatFlagsException;
import java.util.TooManyListenersException;

/**
 * Object类当中toString方法的，方法的声明很普通：
 *      public String toString()
 * 没有什么注意的地方，记住它有返回值，并且返回字符串String对象就可以了。
 *
 * 方法的作用:
 * 关于toString方法的作用，在JDK文档中，有详细的说明，主要说以下四点：
 *      1.返回该对象（调用toString方法的对象）的字符串表示。
 *      2.通常，toString方法会返回一个"以文本方式表示"此对象的字符串。
 *      3.结果应是一个简明但易于读懂的信息表达式。
 *      4.建议所有子类都重写此方法。
 *
 * 所以，toString方法的作用非常简单，说白了，把对象转换成字符串，就和它的方法名一样。而且这个字符串要简洁明了，就能够来描述这个对象，而且最后一句话，已经表明了：
 * Java设计者自己都觉得Object类当中的，toString方法的默认实现不是一个最优解，子类可以根据自身情况选择重写它。
 *
 * Object类当中toString方法默认实现:
 *      return getClass().getName() + "@" + Integer.toHexString(hashCode());
 * 字符串是:
 *      hashCode()这个方法是获取对象的哈希值,而默认情况下对象的哈希值
 *          是通过计算对象在堆内存上的地址得到的
 *          所以hashCode()方法的返回值,默认情况下,可以看成是对象的十进制地址值
 *
 *      类的全限定类名 + "@" + 对象的十六进制地址值
 *
 *  实际上,当我们直接打印引用或者让引用参与字符串拼接运算时,
 *          底层都会自动调用该方法
 *          输出的是toString的返回值
 *
 * 以上默认实现,toString会打印对象的地址值,但更多的时候,我们查看对象,更关注属性的取值
 * 所以JDK文档中建议我们重写该方法.
 * 一般情况下,都是按照打印属性的取值,去重写toString方法
 *
 * 注意事项:
 *      1.toString方法不建议手写,如果是为了查看对象的属性取值,建议直接alt + insert生成.
 *      实际开发中,更建议使用StringBuilder/StringBuffer模板
 *          它们的效率更高
 *
 *      2.toString就是单纯的查看属性取值的方法,尽量自动生成
 *          不要手写它
 *          即便是手写,也不要在里面加业务代码,尤其是赋值语句
 *          idea的debug模式,当执行完创建对象,使用对象的语句时,会自动调用toString方法
 *          来打印对象的信息
 *
 *      3.如果类中有引用数据类型成员变量,
 *          那么就继续拼接该成员变量
 *          需要重写它的toString方法
 *
 *
 *       4.toString方法的调用都是隐式调用的
 *          那么有没有必要写出方法调用?
 *          是没有必要,是不可以,还是随便?
 *          不要写出来,因为写出来有空指针异常的风险
 *          不写出来,没有这个风险
 *
 * 以上,总结
 * toString自动生成完事,不要去改它.
 *
 * @since 11:16
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // Student s = new Student(18, 689);
        // System.out.println(s);
        // System.out.println(s + "123");
        // System.out.println(s.age);

        Student s = new Student(18, 600, new Pet("猫"));
        System.out.println(s);

        Student s2 = new Student(18, 500, null);
        System.out.println(s2);
    }
}

class Student {
    int age;
    double score;
    Pet p;

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
    }

    public Student(int age, double score, Pet p) {
        this.age = age;
        this.score = score;
        this.p = p;
    }

    /*@Override
    public String toString() {
        return "Student{" + " age = " + age + ", score = " + score + " }";
    }*/

    /*@Override
    public String toString() {
        // age = 88;
        return "Student{" +
                "age=" + age +
                ", score=" + score +
                '}';
    }*/

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", score=" + score +
                ", p=" + p +
                '}';
    }
}

class Pet {
    String breed;

    public Pet(String breed) {
        this.breed = breed;
    }

    @Override
    public String toString() {
        return "Pet{" +
                "breed='" + breed + '\'' +
                '}';
    }
}
